package vmap

import (
	"encoding/json"
	"reflect"
	"sort"
	"strconv"
	"strings"
)

// V 自定义的map类型，用于规范处理json
type V map[string]interface{}
type MapStr map[string]string
type IntMap map[int]string
type MapInt map[string]int
type SortV []V

func (sv SortV) Sort()    { sort.Sort(sv) }
func (sv SortV) Len() int { return len(sv) }

func (sv SortV) Less(i, j int) bool { return sv[i].VInt("_index") < sv[j].VInt("_index") }

func (sv SortV) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }

// NewSortV 初始化SortV
func NewSortV(n int) SortV {
	// fmt.Println(n)
	return SortV(make([]V, n))
}

// Append 向SortV类型追加元素
func AppendSortV(sv SortV, v ...V) SortV {
	m := len(sv)
	n := m + len(v)
	if n > cap(sv) { // if necessary, reallocate
		// allocate double what's needed, for future growth.
		newSortv := NewSortV((n + 1) * 2)
		copy(newSortv, sv)
		sv = newSortv
	}
	sv = sv[0:n]
	copy(sv[m:n], v)
	return sv
}

// Keys 获取map的key，并保存到数组
func (v V) Keys() []string {
	k := make([]string, len(v))
	var i uint64
	for key := range v {
		k[i] = key
		i++
	}
	return k
}

func (v V) Copy(src V) {
	for key := range src {
		v[key] = src[key]
	}
}

//VString 返回字符串
func (v V) VString(k string) string {
	value, ok := v[k]
	if !ok {
		return ""
	}
	switch vv := value.(type) {
	case string:
		return vv
	}
	return ""
}

//VStrings 返回字符串数组
func (v V) VStrings(k string) []string {
	value, ok := v[k]
	if !ok {
		return []string{}
	}
	switch vv := value.(type) {
	case []string:
		return vv
	}
	return []string{}
}

// VInt 获取int类型的值。如果value类型不是int或没有key，返回-1
func (v V) VInt(k string) int {
	value, ok := v[k]
	if !ok {
		return -1
	}
	switch vv := value.(type) {
	case int:
		return vv
	}
	return -1
}

// VInt 获取int类型的值。如果value类型不是int或没有key，返回-1
func (v V) VInt32(k string) int32 {
	value, ok := v[k]
	if !ok {
		return -1
	}
	switch vv := value.(type) {
	case int32:
		return vv
	}
	return -1
}

// VInt64 获取int64类型的值。如果value类型不是int64或没有key，返回0
func (v V) VInt64(k string) int64 {
	value, ok := v[k]
	if !ok {
		return -1
	}
	switch vv := value.(type) {
	case int64:
		return vv
	}
	return -1
}

func (v V) VFloat64(k string) float64 {
	value, ok := v[k]
	if !ok {
		return 0
	}
	switch vv := value.(type) {
	case float64:
		return vv
	}
	return 0
}

//VBool 返回bool类型的值。没有key或值的类型不是bool，返回false
func (v V) VBool(k string) bool {
	value, ok := v[k]
	if !ok {
		return false
	}
	switch vv := value.(type) {
	case bool:
		return vv
	}
	return false
}

// VMap 返回vmap.V类型的值
func (v V) VMap(k string) V {
	value, ok := v[k]
	if !ok {
		return V{}
	}
	switch vv := value.(type) {
	case map[string]interface{}:
		return V(vv)
	case V:
		return vv
	}
	return V{}
}

func (v V) VSortV(k string) SortV {
	value, ok := v[k]
	if !ok {
		return SortV{}
	}
	switch vv := value.(type) {
	case SortV:
		return vv
	}
	return SortV{}
}

//ObjType 获取interface的类型
func (v V) ObjType(k, vtype string) interface{} {
	value, ok := v[k]
	if !ok {
		return nil
	}
	switch value.(type) {
	case string:
		if vtype == "string" {
			return value
		}
	case []string:
		if vtype == "[]string" {
			return value
		}
	case []interface{}:
		if vtype == "[]interface" {
			return value
		}
	case int:
		if vtype == "int" {
			return value
		}
	case int64:
		if vtype == "int64" {
			return value
		}
	case float64:
		if vtype == "float64" {
			return value
		}
	case float32:
		if vtype == "float32" {
			return value
		}
	case map[string]interface{}:
		if vtype == "map" {
			return value
		}
	}

	return nil
}

//Type 返回key所对应值的类型
func (v V) Type(key string) string {
	vv := v[key]
	typeOf := reflect.TypeOf(vv)
	return typeOf.String()
}

//JSON 将map转换为json
func (v V) JSON(name string) []byte {
	var p []byte
	if name != "" {
		p, _ = json.MarshalIndent(V{name: v}, "", "  ")
	} else {
		p, _ = json.Marshal(v)
	}
	return p
}

// Unmarshal 将V转换为其他的结构体
func (v V) Unmarshal(out interface{}) error {
	p, err := json.Marshal(v)
	if err == nil {
		err = json.Unmarshal(p, out)
	}
	return err
}

func (v V) ToString(k string) string {
	value, ok := v[k]
	if !ok {
		return ""
	}
	switch vv := value.(type) {
	case string:
		return vv
	case []string:
		sort.Strings(vv)
		return strings.Join(vv, ",")
	case int:
		return strconv.Itoa(vv)
	case int32:
		return strconv.FormatInt(int64(vv), 10)
	case int64:
		return strconv.FormatInt(vv, 10)
	case float64:
		return strconv.FormatFloat(vv, 'f', -1, 64)
	case float32:
		return strconv.FormatFloat(float64(vv), 'f', -1, 32)
	}

	return ""
}

func (v V) SignStr() string {
	vLen := len(v)
	keys := make([]string, vLen)
	i := 0
	for k := range v {
		keys[i] = k
		i++
	}
	sort.Strings(keys)
	signStr := ""
	for _, k := range keys {
		if k != "sign" {
			signStr += k + "=" + v.ToString(k) + "&"
		}
	}
	return signStr
}
